package redes1.unidade2;

public class CamadaDeEnlace {

	private FuncoesAuxiliares funcaoAuxiliar;

	public CamadaDeEnlace() {
		// this.mensagem = mensagem;
		// camadaDeEnlaceTransmissoraEnquadramentoInsercaoDeBits(bitsDaMensagem);
	}

	/**
	 * @param quadroComRedundancia
	 *            (quadro com bits de controle, acrescentados pela funcao
	 *            camadaDeEnlaceTransmissoraControleDeErroHamming).
	 * @return void - Chama a funcao que envia os bits para a camada fisica.
	 */
	public void camadaDeEnlaceTransmissoraControleDeFluxoGoBakcN(String quadroComRedundancia) {
		String quadroEnviado = null;
		// TODO Auto-generated method stub
		camadaDeEnlaceTransmissoraControleDeErroHamming(quadroEnviado);
	}

	/**
	 * @param 
	 * @return 
	 */
	public void camadaDeEnlaceTransmissoraControleDeErroHamming(String quadro) {
		String quadroAuxiliar = "", palavraCodigo = "", matrizHamming[][];
		int indiceHamming = 1, indiceQuadro = 0, indicesHamming[] = null, tamanhoVerificacao = 0;
		
		while (indiceQuadro < quadro.length()) {

			if (indiceHamming < quadroAuxiliar.length() + 1) { // indeceHamming assume uma potencia de 2 
				indiceHamming += indiceHamming;				  // e nao eh alterado ateh que o tamanho de quadroAuxiliar
			}												  // seja igual ao seu valor

			if ((quadroAuxiliar.length() + 1) == indiceHamming) { // sempre que o tamanho de quadroAuxiliar for igual ao valor
				quadroAuxiliar += " ";							 // de indiceHamming, a proxima posição eh preenchida com espaco
				indiceQuadro--;									 // indiceQuadro decrementa p/ nao perder bit atual
			}
			else {
				quadroAuxiliar += quadro.charAt(indiceQuadro); // se a posicao em quadroAuxiliar nao eh potencia de 2
			}												  // recebe o bit atual do quadro

			indiceQuadro++; // proximo bit do quadro sera lido
		} // fim do while
		
		System.out.println(quadro + "\n" + quadroAuxiliar); // teste

		// define quantos bits as cadeias de verificacao terao
		indiceHamming = 1;
		for (int i = 0; i < quadroAuxiliar.length(); i++) {
			if (i == indiceHamming * 2) {
				tamanhoVerificacao++;
				indiceHamming += indiceHamming;
			}
		} // fim do for

		// captura as posicoes as posicoes onde estarao os bits de verificacao em quadroAuxiliar
		indicesHamming = new int[tamanhoVerificacao + 1];
		indiceHamming = 0;
		for (int i = 0; i < quadroAuxiliar.length(); i++) {
			if (quadroAuxiliar.charAt(i) == ' ') {
				indicesHamming[indiceHamming] = i + 1;
				System.out.println(indicesHamming[indiceHamming]); // teste
				indiceHamming++;
			}
		} // fim do for
		
		// armazena as cadeias de verificacao numa matriz
		// * ERRO: esta armazenando somente os bits de 0 a 5, o correto eh de 2 a 7
		String verificador = "";
		funcaoAuxiliar = new FuncoesAuxiliares();
		matrizHamming = new String[tamanhoVerificacao + 1][tamanhoVerificacao + 1];
		for (int linha = 0; linha < indicesHamming.length; linha++) {
			verificador = funcaoAuxiliar.RepresentaBinariosEmString((char) (indicesHamming[linha])+"");
				for (int coluna = 0; coluna < indicesHamming.length; coluna++) {
					matrizHamming[coluna][linha] = verificador.substring(coluna, coluna + 1);
				}
				verificador = "";
		} // fim do for
		
		// impressao para teste
		for (int i = 0; i < indicesHamming.length; i++) {
			for (int j = 0; j < indicesHamming.length; j++) {
				System.out.print(matrizHamming[i][j]);
			}
			System.out.println();
		}
		
		// camadaDeEnlaceTransmissoraEnquadramentoInsercaoDeBits(quadroComRedundancia);
		
	} // fim de camadaDeEnlaceTransmissoraControleDeErroHamming

	/**
	 * @param
	 * @return
	 */
	public void camadaDeEnlaceTransmissoraEnquadramentoInsercaoDeBits(String pacote) {
		String quadro = null,
		// array de tamanho equivalente 'a quantidade de bytes da cadeia
		arrayAuxiliar[] = new String[pacote.length() / 8], quadroAuxiliar = "", // armazena
																				// cada
																				// quadro
																				// temporariamente
		byteAuxiliar = "", // armazena cada byte temporariamente
		flag = "01111110"; // '~': delimita cada quadro

		// definicao aleatoria da quantidade de caracteres de cada quadro (1 a
		// 6)
		int quantidadeDeCaracteres = (int) (Math.round(Math.random() * 5) + 1), // cast
																				// de
																				// long
																				// para
																				// int
		contaCaracteres = 0, // conta os bytes percorridos
		caracter = 0, // delimita cada byte da cadeia
		contaUm = 0; // conta os bits 1

		// percorre o array auxiliar ate' o final
		for (int i = 0; i < arrayAuxiliar.length; i++) {
			contaCaracteres++;
			caracter = i * 8; // avanca 1 byte
			// o byte e' acrescentado ao array
			arrayAuxiliar[i] = pacote.substring(caracter, caracter + 8);
			// o byte sera' testado e acrescentado ao quadro atual

			if (arrayAuxiliar[i].equals(flag)) // se o byte e' igual ao flag
			{
				// percorre os bits do byte
				for (int bit = 0; bit < arrayAuxiliar[i].length(); bit++) {
					// byte temporario recebe um bit do byte
					byteAuxiliar += arrayAuxiliar[i].substring(bit, bit + 1);

					// se o bit acrescentado e' igual a 1
					if (arrayAuxiliar[i].substring(bit, bit + 1).equals("1")) {
						contaUm++; // contaUm e' incrementado
					}
					// se o bit acrescentado e' igual a 0
					else if (arrayAuxiliar[i].substring(bit, bit + 1).equals(
							"0")) {
						contaUm = 0; // contaUm e' zerado
					}
					if (contaUm == 5) // quando contaUm chegar a 5
					{
						byteAuxiliar += "0"; // um bit 0 e' acrescentado ao byte
						contaUm = 0; // contaUm e' zerado
					}
				}
				quadroAuxiliar += byteAuxiliar; // o quadro temporario recebe o
												// byte
				byteAuxiliar = ""; // o byte e' esvaziado
			} else // senao, o quadro temporario so' recebe o byte
			{
				quadroAuxiliar += arrayAuxiliar[i];
			}

			// se o contador de caracteres for igual a quantidade definida para
			// o quadro atual,
			// ou se a cadeia de bits terminou
			if (contaCaracteres == quantidadeDeCaracteres
					|| i == arrayAuxiliar.length - 1) {
				System.out.println("Quadro com flags: \n" + flag
						+ quadroAuxiliar + flag);
				camadaDeEnlaceReceptoraEnquadramentoInsercaoDeBits(flag
						+ quadroAuxiliar + flag);
				// paraMostraEnquadramento += flag + quadroAuxiliar + flag;
				/* mensagemEnquadrada += flag + quadroAuxiliar + flag; */
				quadroAuxiliar = "";
				contaCaracteres = 0;
				quantidadeDeCaracteres = (int) (Math.round(Math.random() * 5) + 1);
			}
		}
		// g_aplicacao.MostraEnquadramento(paraMostraEnquadramento);
		/* return mensagemEnquadrada; */
		// fim do metodo CamadaDeEnlaceTransmissoraEnquadramentoInsercaoDeBits
	}

	/**
	 * @param
	 * @return
	 */
	public void camadaDeEnlaceReceptoraEnquadramentoInsercaoDeBits(String mensagemEnquadrada) {
		String mensagemDesenquadrada = "", quadro = "", flag = "01111110";
		boolean dadoEhFlag = false;
		int contaUm = 0, bit = 0;

		while (bit < mensagemEnquadrada.length()) {
			if (mensagemEnquadrada.charAt(bit) == '1') {
				contaUm++;
			} else {
				contaUm = 0;
			}

			quadro += mensagemEnquadrada.substring(bit, bit + 1);

			if (quadro.endsWith(flag)) {
				if (dadoEhFlag) {
					mensagemDesenquadrada += quadro.substring(0);
					quadro = "";
					dadoEhFlag = false;
				} else {
					mensagemDesenquadrada += quadro.substring(0,
							quadro.length() - 8);
					quadro = "";
				}
			}
			if (contaUm == 5) {
				if (mensagemEnquadrada.charAt(bit + 1) == '0') {
					bit++;
					dadoEhFlag = true;
				}
				contaUm = 0;
			}
			bit++;
		}
		System.out.println("Quadro sem flags: \n" + mensagemDesenquadrada);
		// camadaDeEnlaceReceptoraControleDeErroHamming(mensagemDesenquadrada);
	}

	/**
	 * @param
	 * @return
	 */
	public void camadaDeEnlaceReceptoraControleDeErroHamming(String quadroComRedundancia) {
		String quadroSemRedundancia = null;
		// TODO Auto-generated method stub
		camadaDeEnlaceReceptoraControleDeFluxoGoBakcN(quadroSemRedundancia);
	}

	/**
	 * @param
	 * @return
	 */
	public void camadaDeEnlaceReceptoraControleDeFluxoGoBakcN(String fluxoDeBits) {
		String quadroRecebido = null;
		// TODO Auto-generated method stub
		// enviar para a camada de rede
	}

}